#ifndef LogeD_H_
#define LogeD_H_
#include <vector>

#include <vector>
#include <string>
#include <fstream>  
#include <ratio>
#include <chrono>
#include <mutex>
#include <thread>
#include <iostream>

#ifdef WIN32
#include <io.h>
#include <direct.h>

#else

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <malloc.h>
#include <dirent.h>
#include <string.h>


#endif


#include <functional>

////////////可以单独////////////////

#include <stdio.h>
#include <list>
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
#include <condition_variable>

using namespace std;

template<typename T>
class TaskQueue {
public:
	TaskQueue()
	{

	}
	template<typename C>
	void push_task(C&& task_func) {
		{
			lock_guard<std::mutex> lock(_mutex);
			_queue.emplace_back(std::forward<C>(task_func));
			_condition.notify_one();
		}

	}
	template<typename C>
	void push_task_first(C&& task_func) {

		{
			lock_guard<std::mutex> lock(_mutex);
			_queue.emplace_front(std::forward<C>(task_func));
			_condition.notify_one();

		}

	}

	bool get_task(T& tsk) {

		unique_lock<std::mutex> lock(_mutex);
		_condition.wait(lock, [&]()->bool { return _queue.size() > 0; }); // suspend and wait ...															  //改成右值引用后性能提升了1倍多！
		//tsk = std::move(_queue.front());
		if (_queue.size() > 0)
		{
			tsk = _queue.front();
			_queue.pop_front();
			return true;
		}
		else
		{
			return false;
		}
	}
	uint64_t size() const {
		lock_guard<decltype(_mutex)> lock(_mutex);
		return _queue.size();
	}
private:

	std::list<T> _queue;
	std::mutex _mutex;
	std::condition_variable _condition;
};

////////////////////////////


enum LevelEnum
{
	mTrace,
	mDebug,
	mInfo,
	mWarn,
	mError
};
struct LogConfig
{
	
	// m_is_Synchronize 默认true同步写日志， false 异步写，性能更好
	// m_is_WriteToTerminal 默认true, 同时在终端上显示 false 只写文件，在终端不显示
	// m_logDir 日志的目录，若是多级目录，请手动创建，若是一级，会自动创建
	// m_oneLogFileSize 每个日志文件的大小
	// m_maxFileSize 最多创建的日志个数
	// m_LevelEnum 日志级别，大于等于该级别的会打印到文件

	LogConfig()
	{
		m_is_Synchronize = true;
		m_is_WriteToTerminal = true;
		m_logDir = "./log";
		m_oneLogFileSize = 1024 * 1024 * 5;
		m_maxFileSize = 10;
		m_LevelEnum = mTrace;
	}
	bool m_is_Synchronize;
	bool m_is_WriteToTerminal;
	int m_oneLogFileSize;
	int m_maxFileSize;
	LevelEnum m_LevelEnum;

	std::string m_logDir;
};


class LogeD
{

public:

	static LogeD& Instance();
	static long long getCurrentMs();
	static std::string GetLastName(const char* fileName);
	static std::string getCurrentSystemTime();
	static std::string GetThreadId();

public:
	~LogeD();

	void SetConfig(LogConfig LogConfig_);
	void logOut(LevelEnum eLevel, std::string& str);
	void CloseLog();

private:

	LogeD();
	void StartRun();
	bool CreateDir();

	int removeOldFile();
	bool CreateFile();

	bool CloseFile();
	void getFiles(std::string cate_dir, std::vector<std::string>& files);

	int logWrite(LevelEnum eLevel, std::string& str);

	void run();

	TaskQueue<std::string> mTaskQueue;

	TaskQueue<std::function<int(LevelEnum mLevel, std::string str)>> mTaskQueueFun;

	bool isExit = false;
	FILE* fp = 0;
	std::mutex mux_file;
	std::thread* m_thread;
	LogConfig m_LogConfig;

	static LogeD m_oInstance;
};


#define  LOGEM(eLevel, ...)  {\
                        char temp[8192] = {0};      \
						sprintf(temp, "%s ", LogeD::getCurrentSystemTime().c_str());  \
						sprintf(temp+strlen(temp), "%s line[%d] ", LogeD::GetLastName(__FILE__).c_str(), __LINE__);  \
						sprintf(temp+strlen(temp), "PID[%s] ", LogeD::GetThreadId().c_str());  \
                        sprintf(temp+strlen(temp), __VA_ARGS__); \
						std::string str_temp(temp); \
						LogeD::Instance().logOut(eLevel, str_temp); \
                    }


#endif

/*

#include <stdio.h>
#include <vector>
#include <list>
#include <iostream>
#include "LogeD.h"

using namespace std;
long long getCurrentMs()
{
	auto time_now = std::chrono::system_clock::now();
	auto duration_in_ms = std::chrono::duration_cast<std::chrono::milliseconds>(time_now.time_since_epoch());

	return duration_in_ms.count();
}

int main()
{
	LogConfig mLogConfig;
	mLogConfig.m_is_Synchronize = false;
	mLogConfig.m_LevelEnum = mError;
	LogeD::Instance().SetConfig(mLogConfig); // 如果不调用，则默认参数

	int num = 100;

	long long aaa = getCurrentMs();
	for (int i = 0; i < 10000; i++)
	{

		LOGEM(mTrace, "i = %d .... \n", i);
	}
	long long bbb = getCurrentMs() - aaa;
	LOGEM(mTrace, "time =   %d ms ", bbb);


	system("pause");

	LogeD::Instance().CloseLog(); // 可以不调用
}

*/
